]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
inputMethod: Check for surrounding text before enabling that capability
authorTakao Fujiwara <tfujiwar@redhat.com>
Sun, 9 Mar 2025 00:40:36 +0000 (09:40 +0900)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 15 Apr 2025 12:26:11 +0000 (12:26 +0000)
While the text input protocol does not have the concept of optional features,
some clients like VTE may lag behind on support for retrieving surrounding
text. This is seen as no surrounding text being set by the client, yet we
invariably enable the SURROUNDING_TEXT capability, giving some IMs the wrong
idea that no text is what there is, thus being free to submit other related
requests like deleting surroundings.

Optionally toggle the SURROUNDING_TEXT capability given the existence of
surrounding text, so that IMs know what to expect on subpar clients. At
a minimum, the surrounding text should be actually the empty string for
empty text fields, on clients that do support it.

Fixes: mutter@27bdf0c577 ("wayland/text-input: Use byte based offset in delete_surrounding_text")
Fixes: mutter@33088d59db ("wayland/text-input: Pass char based offset to ClutterInputFocus")
Fixes: mutter@fb86d5d5b0 ("wayland/text-input: Reset surrounding text values by focus change")
closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3102

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3666>

js/misc/inputMethod.js

index c41a5c49f07e8c99cb79c12ab5d829a196c996c5..31592410380694cc6eb30fcbc2aa15b8499e51f9 100644 (file)
@@ -31,6 +31,9 @@ export const InputMethod = GObject.registerClass({
         this._preeditAnchor = 0;
         this._preeditVisible = false;
         this._hidePanelId = 0;
+        this._surroundingText = null;
+        this._surroundingTextCursor = null;
+        this._surroundingTextAnchor = null;
         this._ibus = IBus.Bus.new_async();
         this._ibus.connect('connected', this._onConnected.bind(this));
         this._ibus.connect('disconnected', this._clear.bind(this));
@@ -50,7 +53,10 @@ export const InputMethod = GObject.registerClass({
     }
 
     _updateCapabilities() {
-        let caps = IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.FOCUS | IBus.Capabilite.SURROUNDING_TEXT;
+        let caps = IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.FOCUS;
+
+        if (this._surroundingText !== null)
+            caps |= IBus.Capabilite.SURROUNDING_TEXT;
 
         if (Main.keyboard.visible)
             caps |= IBus.Capabilite.OSK;
@@ -124,6 +130,12 @@ export const InputMethod = GObject.registerClass({
     }
 
     _onDeleteSurroundingText(_context, offset, nchars) {
+        if (this._surroundingText === null) {
+            log('input-method engines should not call ' +
+                'the delete-surrounding-text API in case ' +
+                'the input context has no SURROUNDING_TEXT capability.');
+            return;
+        }
         try {
             this.delete_surrounding(offset, nchars);
         } catch {
@@ -241,6 +253,13 @@ export const InputMethod = GObject.registerClass({
     }
 
     vfunc_set_surrounding(text, cursor, anchor) {
+        // If the previous input context supports the surrounding-text feature.
+        const prevHasSurrounding = this._surroundingText !== null;
+        // If the current input context supports the surrounding-text feature.
+        const nowHasSurrounding = text !== null;
+        // If the SURROUNDING_TEXT capability is changed.
+        const updateCapabilities = prevHasSurrounding !== nowHasSurrounding;
+
         this._surroundingText = text;
         this._surroundingTextCursor = cursor;
         this._surroundingTextAnchor = anchor;
@@ -250,6 +269,11 @@ export const InputMethod = GObject.registerClass({
             return;
 
         let ibusText = IBus.Text.new_from_string(text);
+
+        if (updateCapabilities)
+            this._updateCapabilities();
+
+        // Call context.set_surrounding_text() after context.set_capabilities().
         this._context.set_surrounding_text(ibusText, cursor, anchor);
     }